#!/usr/bin/python2
# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 CourseRoster contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


__author__ = "antiAgainst@gmail.com"


import base64

import urllib
import cookielib
import mechanize

import lxml.html.soupparser as sp

from datarepr import *
from authenutils import *


class CoursePKUClient(object):
    """ 
    Client for log in course.pku.edu.cn 
    
    to use, first
        xxx = CoursePKUClient()
    and
        Course.login(some_std_id, some_password)
    then you can
        Course.get_courses()
        Course.get_rosters(list_of_course_uuid)
    """
    
        
    def __init__(self):
        self.br = mechanize.Browser()

        # different parameters of the browser
        self.br.set_handle_equiv(True)
        self.br.set_handle_gzip(False)
        self.br.set_handle_redirect(True)
        self.br.set_handle_referer(True)
        self.br.set_handle_robots(False)

        # print info about http header/response?
        self.br.set_debug_http(False)
        # print info about redirect?
        self.br.set_debug_redirects(False)
        # print debug response?
        self.br.set_debug_responses(False)

        # add firfox-like headers
        self.br.addheaders = [
            ("User-Agent", "Mozilla/5.0 (X11; Linux i686; rv:5.0) Gecko/20100101 Firefox/5.0"), 
            ("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"),
            ("Accept-Language", "en-us,en;q=0.5"), 
            ("Accept-Charset", "gb18030,utf-8;q=0.7,*;q=0.7")]

        self.stdid = "none"

    def login(self, stdid, passwd):
        # create cookie for the current user
        cj = cookielib.CookieJar()
        self.br.set_cookiejar(cj)

        # open the login web page
        self.br.open("http://course.pku.edu.cn/webapps/login/")
        self.br.select_form(name='login')

        one_time_token = self.br['one_time_token']
        md5_passwd = calcMD5(passwd, 8)
        md5_passwd_uni = calcMD5(passwd, 16)

        # set the related entries to writable
        self.br.form.find_control("encoded_pw").readonly = False
        self.br.form.find_control("encoded_pw_unicode").readonly = False

        # fill in the form
        self.br["user_id"] = stdid
        self.br["password"] = base64.urlsafe_b64encode(passwd)
        self.br["encoded_pw"] = calcMD5(md5_passwd+one_time_token, 8)
        self.br["encoded_pw_unicode"] = calcMD5(md5_passwd_uni+one_time_token, 16)

        # submit the form
        self.br.submit()

        self.stdid = stdid

    def get_courses(self):
        """ get a student's all courses """
        self.br.open("http://course.pku.edu.cn/webapps/portal/tab/_1_1/index.jsp")

        body = self.br.response().read()
        dom = sp.fromstring(body)

        # course ID <--> name dict
        course_name = CourseDict(self.stdid)

        for course in dom.xpath("//a[@target]"):
            # course name
            name = course.text.split(":")
            if len(name) == 1: continue
            name = name[1].strip()
            # course ID
            id = course.get("href").strip()
            id = urllib.unquote(id)
            id = id[id.index("&id=")+4:]
            id = id[:id.index("&")]

            course_name[id] = name
            
        return course_name

    def get_rosters(self, courses):
        """ 
        get all classmates' information of a stdent

        parameters:
        courses: a list containing course-uuids
        """
        import re
        course_roster = RosterAlbum(stdid=self.stdid)

        for id in courses:
            # get the number of classmates
            self.br.open("http://course.pku.edu.cn/bin/common/search.pl?"
                         "action=RESULTS&context=USERBYCOURSE&type=LISTALL"
                         "&operation=VIEW&course_id=%s" % id)
            body = self.br.response().read()
            dom = sp.fromstring(body)
            # number of students
            std_count = dom.xpath('//font[@class="fnt0"][@size=3]')[0].text
            std_count = int(re.sub(r"[\D]", "", std_count))
            # number of pages of roster
            page_count = std_count / 25 + 1
            # roster for the current course
            roster = {}
            for page in range(page_count):
                self.br.open("http://course.pku.edu.cn/bin/common/search.pl?"
                             "action=RESULTS&context=USERBYCOURSE&type=LISTALL"
                             "&cursor=%d&operation=VIEW&course_id=%s" % (page*25, id))
                body = self.br.response().read()
                dom = sp.fromstring(body)

                for i in dom.xpath("//tr"):
                    name=i.xpath('td[@headers="name"]/font/a')
                    if name:
                        crsusr_id = name[0].get('href')
                        crsusr_id = crsusr_id[crsusr_id.index("&crsusrs_pk=")+12:]
                        crsusr_id = crsusr_id[:crsusr_id.index("&")]
                        email = i.xpath('td[@headers="e-mail"]/font/a')
                        email = email[0].text if email else ""
                        name = name[0].text
                        roster[crsusr_id] = (name, email)
            course_roster[id] = roster

        return course_roster

def fetch_demo():
    """ demo: get a student's courses and rosters """
    import getpass

    stdid = raw_input("[studentID]:")
    passwd = getpass.getpass("[password]:")
    client = CoursePKUClient()
    client.login(stdid, passwd)

    courses = client.get_courses()
    print courses

    rosters = client.get_rosters(courses.keys())
    print rosters

if __name__ == "__main__":
    fetch_demo()


__all__ = ['CoursePKUClient']
